#ifndef __HELPER__
#define __HELPER__


namespace xm
{
	struct CodeToStream : IKBCoderHook 
	{
		xm::iptr<IKBStream> _out;
		CodeToStream( IUnknown * target ) : _out(target){};
		virtual HRESULT OnCodeFrame( cblob_t inp, cblob_t outp )
		{
			SIZE_T eff = 0;
			RFAILED( _out->Write( outp.Data, outp.Length, &eff ) );
			RASSERT( eff == outp.Length, E_FAIL );
			return S_OK;
		}
	};

	struct CalcCodeRate : IKBCoderHook 
	{
		UINT64 InBytes, OutBytes;
		CalcCodeRate() : InBytes(0), OutBytes(0) {}
		virtual HRESULT OnCodeFrame( cblob_t inp, cblob_t outp )
		{
			InBytes += inp.Length;
			OutBytes += outp.Length;
			return S_OK;
		}
		DOUBLE GetRate()
		{
			return (DOUBLE)OutBytes/(DOUBLE)InBytes;
		}
	};

	template < SIZE_T FRAME_SIZE >
	static HRESULT CodeTo( IKBCoderLL * code, IKBStream * ins, UINT64 size, IKBCoderHook * hook )
	{
		UTIL::sentry<UINT8*> buffer = new UINT8[FRAME_SIZE];
		if( !buffer ) return E_FAIL;
		RFAILED( code->Start( 0, 0, hook ) );
		while( size )
		{
			SIZE_T toRead = FRAME_SIZE < size ? FRAME_SIZE : (SIZE_T)size;
			SIZE_T eff = 0;
			RFAILED( ins->Read( buffer, toRead, &eff ) );
			if( !eff ) break;
			RFAILED( code->CodeIt( buffer, eff ) );
			size -= eff;
		}
		code->End();
		return S_OK;
	}

	template < SIZE_T FRAME_SIZE >
	static HRESULT CopyTo( IKBStream * from, IKBStream * to )
	{
		UTIL::sentry<UINT8*> buffer = new UINT8[FRAME_SIZE];
		if( !buffer ) return E_FAIL;
		while(1)
		{
			SIZE_T eff = 0, wc = 0;
			RFAILED( from->Read( buffer, FRAME_SIZE, &eff ) );
			if( !eff ) break;
			RFAILED( to->Write( buffer, eff, &wc ) );
			if( eff != wc ) return E_FAIL;
		}
		return S_OK;
	}

};



#endif